﻿using BattleFury.Lib.Graphics;
using BattleFury.Lib.Maps;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;

namespace BattleFury.Lib.Lights
{
	public class LightLayer	: ILayer
	{
		private RenderTarget2D _renderTarget;
		private Texture2D _clearTexture;

		public static BlendState Multiply { get; private set; }
		public static BlendState AlphaWrite { get; private set; }
		public static BlendState AlphaMultiply { get; private set; }
		
		public string Name { get; set; }
		public bool IsEnabled { get; set; }
		public bool IsVisible { get; set; }
		public Vector2 Size { get; private set; }
		public Texture2D LightTexture { get; set; }
		public Color AmbientLightColor { get; set; }
		public Camera Camera { get; set; }

		public List<Light> Lights { get; set; }
		private List<string> _lightNames { get; set; } 

		public Light this[string name]
		{
			get
			{
				var index = _lightNames.IndexOf(name);
				return Lights[index];
			}
		}

		public RenderEngine Engine
		{
			get { return RenderEngine.Get(); }
		}
		
		public LightLayer()
		{
			Lights = new List<Light>();
			_lightNames = new List<string>();

			var graphicsDevice = Engine.GraphicsDevice;
			var pp = graphicsDevice.PresentationParameters;
			_renderTarget = new RenderTarget2D(graphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, pp.BackBufferFormat, pp.DepthStencilFormat, pp.MultiSampleCount, RenderTargetUsage.DiscardContents);
			_clearTexture = Engine.Content.Load<Texture2D>(".\\gfx\\Lights\\AlphaOne");
			LightTexture = Engine.Content.Load<Texture2D>(".\\gfx\\Lights\\Light");

			AmbientLightColor = new Color(50, 50, 50, 255);

			Multiply = new BlendState();
			Multiply.ColorSourceBlend = Multiply.AlphaSourceBlend = Blend.Zero;
			Multiply.ColorDestinationBlend = Multiply.AlphaDestinationBlend = Blend.SourceColor;
			Multiply.ColorBlendFunction = Multiply.AlphaBlendFunction = BlendFunction.Add;

			AlphaWrite = new BlendState
			{
				ColorWriteChannels = ColorWriteChannels.Alpha
			};

			AlphaMultiply = new BlendState();
			AlphaMultiply.ColorDestinationBlend = AlphaMultiply.AlphaDestinationBlend = Blend.One;
			AlphaMultiply.ColorSourceBlend = AlphaMultiply.AlphaSourceBlend = Blend.DestinationAlpha;

			IsEnabled = true;
			IsVisible = true;
		}

		public void Update(GameTime gameTime)
		{
			if (!IsEnabled) return;

			var graphicsDevice = Engine.GraphicsDevice;
			var spriteBatch = Engine.SpriteBatch;
			graphicsDevice.SetRenderTarget(_renderTarget);

			graphicsDevice.Clear(AmbientLightColor);

			foreach (var light in Lights)
			{
				ClearAlpha();

				graphicsDevice.RasterizerState = RasterizerState.CullNone;
				graphicsDevice.BlendState = AlphaWrite;

				spriteBatch.Begin(SpriteSortMode.Immediate, AlphaMultiply);
					light.Draw(spriteBatch);
				spriteBatch.End();
			}

			ClearAlpha();

			graphicsDevice.SetRenderTarget(null);
		}

		private void ClearAlpha()
		{
			var spriteBatch = Engine.SpriteBatch;
			var graphicsDevice = Engine.GraphicsDevice;
			spriteBatch.Begin(SpriteSortMode.Immediate, AlphaWrite);
				spriteBatch.Draw(_clearTexture, new Rectangle(0, 0, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height), Color.White);
			spriteBatch.End();
		}

		public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
		{
			if (!IsVisible) return;

			spriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
				spriteBatch.Draw(_renderTarget, Vector2.Zero, Color.White);
			spriteBatch.End();
		}

		public Vector2 GetLocation(Vector2 absoluteLocation)
		{
			throw new System.NotImplementedException();
		}

		public Light AddLight(string name, Color color, float range, Vector2 position)
		{
			var ret = new Light(LightTexture, color, range, position);
			Lights.Add(ret);
			_lightNames.Add(name);
			return ret;
		}

		public void Remove(string name)
		{
			var index = _lightNames.IndexOf(name);
			Lights.RemoveAt(index);
			_lightNames.RemoveAt(index);
		}
	}
}
